#ifndef IMGRAPHICSINTERFACES_H
#define IMGRAPHICSINTERFACES_H

#include <Core.h>
#include <Config.h>
#include "imMaths.h"
#include "imGeometryBase.h"

#define NUMTEXTURES 3

namespace imGraphics {
	//
	// Texture formats
	//
	typedef enum TexFormats {
		TFMT_UNKNOWN = 0,
		TFMT_R8G8B8X8 = 1,
		TFMT_R8G8B8A8 = 2,
		TFMT_R16G16B16X16 = 3,
		TFMT_R24X8 = 4,
		TFMT_R32 = 5
	} TexFormat;

	// Blend modes
	typedef enum BlendAlphas {
		BM_NONE,
		BM_ONE,
		BM_SRCALPHA,
		BM_INVSRCALPHA,
		BM_DESTALPHA,
		BM_INVDESTALPHA
	} BlendAlpha;

	// Backface culling modes
	typedef enum BackfaceCullModes {
		BFC_NONE,
		BFC_CW,
		BFC_CCW
	} CullMode;

	// Display modes
	typedef enum RenderDisplayModes {
		DSP_WINDOW = 1,			// Standard window mode
		DSP_WINDOWNOBORDER = 2,	// Window mode with no border, at native res emulates fullscreen while making alt+tab easy to use
		DSP_FULLSCREEN = 0		// Fullscreen mode
	} DisplayMode;

	// Texture channels
	typedef enum TextureChannels {
		TEX_DIFFUSE,
		TEX_SPECULAR,
		TEX_NORMAL
	} TexChannel;

	// Mesh Driver
	// Bridge for meshes in imGeometry and the API
	class iMeshDriver {
	public:
		virtual void Hook(Vertex* _Verts, unsigned int _NumVerts, void* _Indices, unsigned int _NumIndices, unsigned int _IndexSize) = 0;
		virtual void Predraw(void) = 0; // In D3D, ties the data sources into the device
		virtual void Draw(int Subset) = 0; // Calls the draw function
		// The last two are separated for situations where rendering can be accelerated by
		// reusing index and vertex data, such as instancing.
	};

	//
	// Shader
	// Interface for material effects. Setting textures, blending, etc.
	class iShader : public iMMObj {
	public:
		virtual void LoadShader(char* Path) = 0;

		// Colours
		virtual void SetDiffuse(const Vector4 &Diffuse) = 0;
		virtual void SetSpecular(const Vector4 &Specular) = 0;

		// Blending modes
		virtual void SetSrcBlend(const BlendAlpha &SrcBlend) = 0;
		virtual void SetDestBlend(const BlendAlpha &DestBlend) = 0;

		// Misc. rendering options
		virtual void SetWireframe(const bool &Wireframe) = 0;
		virtual void SetCullMode(const CullMode &Mode) = 0;

		virtual void FillMatrices() = 0;
		virtual void StartRender() {};
		virtual void EndRender() {};
	};

	//
	// Texture object
	// Just bitmap textures
	class iTexture : public iFile, public iMMObj {
	protected:
		std::string m_FilePath;
	public:
		virtual void LoadFromFile(std::string &Path) = 0;
		virtual void Release() = 0;
		virtual void FillSolid(Vector4 &Col) = 0;
		
		virtual void UseTexture(int Channel) = 0;

		std::string GetFilePath() {return m_FilePath;}
	};

	//
	// Render Target
	// Useful for rendering effects like shadow mapping and HDR

	class iRenderTarget {
	public:
		virtual void Init(void) = 0;
		virtual void Release(void) = 0;

		virtual void SetRes(int w, int h) = 0;
		virtual void SetFormat(TexFormat) = 0;
		virtual void UseDepth(bool, TexFormat) = 0;
		virtual void AutoGenMipMaps(bool) = 0;

		virtual void BeginScene(void) = 0;
		virtual void EndScene(void) = 0;

		virtual void* GetTexture(void) = 0;
	};

	//
	// Renderer
	// Interface for the graphics driver (OpenGL, D3D, etc.)
	class iRenderer {
	public:
		virtual void Init (HINSTANCE, HWND) = 0;
		virtual void Init () = 0;
		virtual void Release () = 0;
		virtual void Cleanup () = 0;

		virtual void SetRes(unsigned int w, unsigned int h) = 0;
		virtual void SetMode(DisplayMode Mode) = 0;
		virtual void SetVSync(bool vSync) = 0;

		virtual void SetupFromFile(Config* Cfg) = 0;
		
		virtual void SetWorldMatrix(Matrix &NewWorld) = 0;
		virtual void SetViewMatrix(Matrix &NewView) = 0;
		virtual void SetProjectionMatrix(Matrix &NewProjection) = 0;

/* This particular object acts as the receptionist for the graphics DLL, and these
next few functions illustrate that nicely. All the miscellaneous objects we will
use from the graphics library are first initialized by the iRenderer object, and
then passed back through here*/
		virtual iMeshDriver* GetMeshDriver() = 0;
		virtual iRenderTarget* GetNewRenderTarget() = 0;
		virtual iShader* GetNewShader() = 0;
		virtual iTexture* GetNewTexture() = 0;

		virtual void StartFrame() = 0;
		virtual void EndFrame() = 0;

		virtual void CheckAllFiles() = 0;	// These are links to misc. functions only
		virtual void CollectGarbage() = 0;	// accessible within the .DLL
	};

	// Memory management pointers
	typedef MMPtr<imGraphics::iTexture> pTexture;
	typedef MMPtr<imGraphics::iShader> pShader;
}

#endif